/**************************************************************************
*   Copyright (C) 2010 Chernov Dmitry                                     *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/

#ifndef MARBLEGAMESOLVER_H
#define MARBLEGAMESOLVER_H

#include <string>
#include <map>
#include <deque>

#include "windows.h"

#include "MarbleTask.h"


/*
 * Class which serves as thread pool and task manager
 * for solving marble game in parralel
 *
 */
class MarbleGameSolver
{
public:
    /*
     * If threadCount more than 0 solves game in several threads
     *
     */
    MarbleGameSolver( int threadCount = 0 );
    ~MarbleGameSolver();

    /*
     * Returns solution for given task
     *
     */
    std::string findShortestSolution( const std::string& task );

private:

    friend class MarbleTask;
    static DWORD WINAPI threadProc( LPVOID pParam );

    /*
     * In multithreaded version ain't gonna work less
     * than this time
     *
     */
    static const int THREAD_WAIT_INTERVAL = 50;

    /*
     * For solution saving
     *
     */
    std::string m_shortestNow;
    CRITICAL_SECTION m_saveCS;
    void saveSolution( const std::vector<MarbleTask::direction>& sol );
    int yetShortestSol();

    /*
     * Marble tasks
     *
     */
    std::deque<MarbleTask> m_taskQueue;
    CRITICAL_SECTION m_taskCS;
    void tryRunTask();
    void addMarbleTask( MarbleTask* gm );

    /*
     * Struct which holds data needed for thread management
     *
     */
    struct ThreadData
    {
        bool	m_free;
        HANDLE	m_waitHandle;
        HANDLE	m_thread;
        DWORD	m_threadId;
    };

    typedef std::map< DWORD, ThreadData, std::less<DWORD>, std::allocator<ThreadData> > ThreadMap;

    /*
     * Thread stuff
     *
     */
    int m_threadCount;
    ThreadMap m_threads;
    bool m_isDestroying;
    bool m_started;
    HANDLE m_notifyShutdown;
    CRITICAL_SECTION m_poolCS;

    bool spawnThreads();
    void destroyThreads();
    void start();

    void finishNotify( DWORD dwThreadId );

    HANDLE getWaitHandle( DWORD dwThreadId );
    HANDLE getShutdownHandle();
    bool checkThreadStop();

    int getWorkingThreadCount();
    bool freeThreadsPresent();

    bool stillUndone();
};

#endif // MARBLEGAMESOLVER_H
